package com.pureland.ucc.config.oauth;

import com.pureland.security.ResourceAuthExceptionEntryPoint;
import com.pureland.security.filter.DefaultClientCredentialsTokenEndpointFilter;
import com.pureland.ucc.service.impl.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.oauth2.common.DefaultOAuth2AccessToken;
import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.ClientDetailsService;
import org.springframework.security.oauth2.provider.CompositeTokenGranter;
import org.springframework.security.oauth2.provider.OAuth2RequestFactory;
import org.springframework.security.oauth2.provider.TokenGranter;
import org.springframework.security.oauth2.provider.token.AuthorizationServerTokenServices;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.InMemoryTokenStore;

import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

/**
 * @projectName: pureland_cloud
 * @className: com.pureland.ucc.config.oauth.AuthorizationServerConfigurer
 * @description: 授权配置类
 * @author: tong.li
 * @createTime: 2020/11/18 14:41
 * @version: v1.0
 * @copyright: 版权所有 李彤 © 2020
 */
@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfigurer extends AuthorizationServerConfigurerAdapter {

    @Autowired
    private AuthenticationManager authenticationManager;

    @Autowired
    private UserService userService;

    @Bean
    public TokenStore  tokenStore() {
        return new InMemoryTokenStore();
    }


    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        clients.inMemory().withClient("test").secret(new BCryptPasswordEncoder().encode("test"))
                .scopes("all")
                // 设置token的有效期为30分钟
                .accessTokenValiditySeconds(1800)
                // 设置刷新token有效期为1个小时
                .refreshTokenValiditySeconds(3600)
                .authorizedGrantTypes("authorization_code", "refresh_token", "client_credentials", "password", "sms");
    }

    @Autowired
    private ResourceAuthExceptionEntryPoint customAuthenticationEntryPoint;


    @Override
    public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
        DefaultClientCredentialsTokenEndpointFilter endpointFilter = new DefaultClientCredentialsTokenEndpointFilter();
        endpointFilter.setConfigurer(security);
        endpointFilter.afterPropertiesSet();
        endpointFilter.setAuthenticationEntryPoint(customAuthenticationEntryPoint);
        // 客户端认证之前的过滤器
        security.addTokenEndpointAuthenticationFilter(endpointFilter);
        // 为什么要注释掉，原因请看:https://blog.csdn.net/dechengtju/article/details/107775360
        /*
         security.allowFormAuthenticationForClients()
                .tokenKeyAccess("permitAll()").checkTokenAccess("isAuthenticated()");
         */

    }



    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        endpoints.authenticationManager(authenticationManager);
        List<TokenGranter> tokenGranters = getTokenGranters(endpoints.getTokenServices(), endpoints.getClientDetailsService(), endpoints.getOAuth2RequestFactory());
        // 设置授权类型列表,将原来的授权类型Password也加入进去
        TokenGranter tokenGranter = endpoints.getTokenGranter();
        tokenGranters.add(tokenGranter);
        endpoints.tokenGranter(new CompositeTokenGranter(tokenGranters));
        endpoints.tokenStore(tokenStore()).authenticationManager(authenticationManager);
        // 设置扩展信息
        endpoints.tokenEnhancer((accessToken, authentication) -> {
            DefaultOAuth2AccessToken token = (DefaultOAuth2AccessToken) accessToken;
            UserDetails userDetails = (UserDetails) authentication.getPrincipal();
            Map<String,Object> map = new LinkedHashMap<>();
            map.put("username",userDetails.getUsername());
            token.setAdditionalInformation(map);
            return accessToken;
        });

    }

    private List<TokenGranter> getTokenGranters(AuthorizationServerTokenServices tokenServices,
                                                ClientDetailsService clientDetailsService, OAuth2RequestFactory requestFactory) {
        List list = new ArrayList();
        // 短信登录方式
        list.add(new SmsTokenGranter(tokenServices, clientDetailsService, requestFactory,
                userService));
        // 密码登录方式
        list.add(new PasswordTokenGranter(tokenServices, clientDetailsService, requestFactory,
                userService));
        return list;
    }



}
